package com.example.service.impl.pc.aps;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.entity.mysql.Productprocessresource;
import com.example.entity.mysql.Resourcegroup;
import com.example.entity.mysql.WorkCalendar;
import com.example.entity.mysql.Workresource;
import com.example.entity.vo.pc.PCListVo;
import com.example.entity.vo.pc.ResourceGroupLoadVo;
import com.example.entity.yifei.Bommf;
import com.example.entity.yifei.Mocty;
import com.example.exception.CustomException;
import com.example.mapper.WorkCalendarMapper;
import com.example.service.BommfService;
import com.example.service.MoctyService;
import com.example.service.WorkCalendarService;
import com.example.service.pc.ResourcegroupService;
import com.example.service.pc.WorkresourceService;
import com.example.service.pc.aps.ApsService;
import com.example.untils.TimeUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

@Service
public class ApsServiceImpl implements ApsService {
    @Resource
    private BommfService bommfService;

    @Resource
    private WorkCalendarService workCalendarService;

    @Resource
    private WorkCalendarMapper workCalendarMapper;

    @Resource
    private ResourcegroupService resourcegroupService;

    @Resource
    private MoctyService moctyService;

    @Resource
    private WorkresourceService workresourceService;

    /**
     * 工单工序分配时间，从瓶颈工序，按两边分。只需要考虑某一天的节拍，往两边扩
     */
    @Override
    public void apsMocta(List<PCListVo> list) {
        if(list == null || list.size() == 0) return;
        ArrayList<Double> qzSum = new ArrayList<>();  // 前置天数数组
        ArrayList<Double> hzSum = new ArrayList<>();  // 后置天数数组
        ArrayList<Double> yuanQzSum = new ArrayList<>();  // 原来的前置天数数组
        ArrayList<Double> yuanHzSum = new ArrayList<>();  // 原来的后置天数数组
        hzSum.add(0D);  // 从下标1开始，下标0没有意义
        qzSum.add(0D);
        yuanQzSum.add(0D);
        yuanHzSum.add(0D);
        // 预处理前缀和数组
        for(PCListVo vo : list) {
            Bommf bommf = bommfService.getOne(new LambdaQueryWrapper<Bommf>().eq(Bommf::getMf001, vo.getProductId())
                    .eq(Bommf::getMf003, vo.getProcessNo()).eq(Bommf::getMf004, vo.getProcessId()));
            qzSum.add(qzSum.get(qzSum.size() - 1) +
                    Double.max(hzSum.get(hzSum.size() - 1), bommf.getUdf08() == null ? 0 : Double.parseDouble(bommf.getUdf08())));
            double mf014 = bommf.getMf014() == null ? 0 : bommf.getMf014().doubleValue();
            hzSum.add(hzSum.get(hzSum.size() - 1) + mf014);
            yuanQzSum.add(Double.parseDouble(bommf.getUdf08()));
            yuanHzSum.add(bommf.getMf014().doubleValue());
        }
        int maxn = hzSum.size() - 1;
//        if(list.size() > 2) {   // 后置天数数组
//            for(int i = list.size() - 2; i > 0; i--) {
//                hzSum.add(hzSum.get(i + 1) + hzSum.get(i));
//            }
//        }
        int idx = 0;
        // 找到瓶颈工序（节拍最大的）
        for(int i = 1; i < list.size(); i++) {
            if(list.get(i).getBeat().compareTo(list.get(idx).getBeat()) > 0) {
                idx = i;
            }
        }
        // 先对瓶颈工序进行排产
        // 1.计算可用的时间区间。
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 获取年、月、日值
        int year = currentDate.getYear();
        int month = currentDate.getMonthValue();
        int day = currentDate.getDayOfMonth();
        // 计算最早哪天可以开工：前工序（含本工序）的前置天数之和+前工序的落后天数之后
        String l = TimeUtils.addOrSubtract(year, month, day, (int)(hzSum.get(idx) - hzSum.get(0) + qzSum.get(Math.max(idx + 1, maxn)) - qzSum.get(0)));   // idx是从零开始的，所以需要加一
        String orderDate = list.get(idx).getOrderDate();
        // 根据后工序(含本工序)的落后天数以及后工序的前置天数之和,计算最晚能排到哪天
        String r = TimeUtils.addOrSubtract(Integer.parseInt(orderDate.substring(0, 4)),
                Integer.parseInt(orderDate.substring(4, 6)), Integer.parseInt(orderDate.substring(6, 8)), (int)(hzSum.get(maxn) - hzSum.get(Math.max(idx, maxn)) + qzSum.get(maxn) - qzSum.get(Math.max(idx + 1, maxn))));
        // 先除去节假日
//        List<WorkCalendar> calendarList = workCalendarService.list(new LambdaQueryWrapper<WorkCalendar>()
//                .eq(WorkCalendar::getWorkCenter, list.get(0).getWorkCenter()).between(WorkCalendar::getDate, l, r));
        if(list.get(idx).getWorkCenter() == null) {
            throw new CustomException("500", "该工单工序没有工作中心！！");
        }
//        List<WorkCalendar> calendarList = workCalendarMapper.getListByLR(l, r, list.get(idx).getWorkCenter());
//        schedule(list.get(idx), calendarList, 0);
    }

    /**
     * 排日期数量和使用什么资源组
     * @param pcVo
     * @param calendarList
     * @param status  0 表示排的时候，不用考虑其他工序， 1 表示需要考虑上一道工序，-1 表示需要考虑下一道工序
     */
    private void schedule(PCListVo pcVo, List<WorkCalendar> calendarList, Integer status) {
        List<Productprocessresource> resourceList = pcVo.getResourceList();
        resourceList.sort(new Comparator<Productprocessresource>() {
            @Override
            public int compare(Productprocessresource o1, Productprocessresource o2) {
                if(o1.getPrimaryCode() != null && o1.getPrimaryCode().equals(1)) return 1;
                if(o2.getPrimaryCode() != null && o2.getPrimaryCode().equals(1)) return -1;
                return 0;
            }
        });
        // 计算出 日期可使用时间的，前缀和
        List<Double> preTime = new ArrayList<>();
        preTime.add(0D);  // 下标以1开始
        for(WorkCalendar workCalendar : calendarList) {
            preTime.add(preTime.get(preTime.size() - 1) + workCalendar.getRealWorkTime());
        }

        if(status.equals(0)) {
            Boolean flag = false;
            for(int i = 0; i < calendarList.size(); i++) {
                // 获取设备组中末级数量
                int count = resourcegroupService.count(new LambdaQueryWrapper<Resourcegroup>()
                        .eq(Resourcegroup::getResourceGroupParentId, resourceList.get(0).getResourceGroupId()).eq(Resourcegroup::getType, "F"));
                List<ResourceGroupLoadVo> load = resourcegroupService.getResourceGroupLoad(resourceList.get(0).getResourceGroupId(), calendarList.get(i).getDate(), calendarList.get(i).getDate());
                // 实际能用的时间 * 需要乘上设备组的数量
                if(load == null || load.size() == 0 || load.get(0).getLoadTime().compareTo(new BigDecimal(count * calendarList.get(i).getRealWorkTime())) < 0) {
                    // 从这个日期开始，全部往前排。（直接拉到最长, 这样子使用的设备数量会最少）
                    int j = i + 1;  // 从1开始数是第几个
                    Double zs = Math.ceil(pcVo.getSum());  // 工单的总数
                    Double zhi = preTime.get(j) - preTime.get(0);
                    // 计算所需要的台数
                    int ts = (int) Math.ceil(pcVo.getSum() * resourceList.get(0).getBeat() / zhi);
                    while(zs > 0 || j > 0) {
                        Double productNums = Math.ceil(ts * calendarList.get(j - 1).getRealWorkTime() / resourceList.get(0).getBeat());
                        if(productNums.compareTo(zs) > 0) {
                            productNums = zs;
                        }
                        zs -= productNums;
                        // Mocty插入数量，然后workResource插入数据
                        Mocty mocty = new Mocty();
                        mocty.setCreateDate(TimeUtils.getNowTime());
                        mocty.setFlag(1D);
                        mocty.setTy001(pcVo.getWorkSingle());
                        mocty.setTy002(pcVo.getWorkNo());
                        mocty.setTy003(calendarList.get(j).getDate());
                        mocty.setTy004(productNums);
                        mocty.setTy009("****");
                        mocty.setTy019(pcVo.getProcessNo());
                        mocty.setUdf05(UUID.randomUUID().toString());
                        moctyService.save(mocty);

                        Workresource workresource = new Workresource();
                        workresource.setWorkSingle(pcVo.getWorkSingle());
                        workresource.setWorkNo(pcVo.getWorkNo());
                        workresource.setProcessNo(pcVo.getProcessNo());
                        workresource.setProcessId(pcVo.getProcessId());
                        workresource.setResourceGroupId(resourceList.get(0).getResourceGroupId());
                        workresource.setDate(calendarList.get(j).getDate());
                        workresource.setBeat(resourceList.get(0).getBeat());
                        workresource.setQuota(resourceList.get(0).getQuota());
                        workresource.setCreator("");

                        workresource.setCreateTime(TimeUtils.getFullNowTime());
                        workresource.setWorkResourceId(UUID.randomUUID().toString());
                        workresource.setProductLineId(mocty.getUdf05());   // 和生产线进行绑定
                        workresourceService.save(workresource);
                        j--;
                    }
                    flag = true;
                    break;
                }
            }
            if(!flag) {
                // 如果一个合适的都没有，则直接从最后的开始
                // 从这个日期开始，全部往前排。（直接拉到最长, 这样子使用的设备数量会最少）
                int j = calendarList.size();
                Double zs = Math.ceil(pcVo.getSum());  // 工单的总数
                Double zhi = preTime.get(j) - preTime.get(0);
                // 计算所需要的台数
                int ts = (int) Math.ceil(pcVo.getSum() * resourceList.get(0).getBeat() / zhi);
                while(zs > 0 || j > 0) {
                    Double productNums = Math.ceil(ts * calendarList.get(j - 1).getRealWorkTime() / resourceList.get(0).getBeat());
                    if(productNums.compareTo(zs) > 0) {
                        productNums = zs;
                    }
                    zs -= productNums;
                    // Mocty插入数量，然后workResource插入数据
                    Mocty mocty = new Mocty();
                    mocty.setCreateDate(TimeUtils.getNowTime());
                    mocty.setFlag(1D);
                    mocty.setTy001(pcVo.getWorkSingle());
                    mocty.setTy002(pcVo.getWorkNo());
                    mocty.setTy003(calendarList.get(j).getDate());
                    mocty.setTy004(productNums);
                    mocty.setTy009("****");
                    mocty.setTy019(pcVo.getProcessNo());
                    mocty.setUdf05(UUID.randomUUID().toString());
                    moctyService.save(mocty);

                    Workresource workresource = new Workresource();
                    workresource.setWorkSingle(pcVo.getWorkSingle());
                    workresource.setWorkNo(pcVo.getWorkNo());
                    workresource.setProcessNo(pcVo.getProcessNo());
                    workresource.setProcessId(pcVo.getProcessId());
                    workresource.setResourceGroupId(resourceList.get(0).getResourceGroupId());
                    workresource.setDate(calendarList.get(j).getDate());
                    workresource.setBeat(resourceList.get(0).getBeat());
                    workresource.setQuota(resourceList.get(0).getQuota());
                    workresource.setCreator("");

                    workresource.setCreateTime(TimeUtils.getFullNowTime());
                    workresource.setWorkResourceId(UUID.randomUUID().toString());
                    workresource.setProductLineId(mocty.getUdf05());   // 和生产线进行绑定
                    workresourceService.save(workresource);
                    j--;
                }
            }
        }else{

        }


    }

}
